// -----------------------------------------------------------------------------
// This source file is part of Matrix Platform
// 	(Universal .NET Software Development Platform)
// For the latest info, see http://www.matrixplatform.com
// 
// Copyright (c) 2009-2010, Ingenious Ltd
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// -----------------------------------------------------------------------------
using System;
using System.Threading;
using Matrix.Framework.SuperPool.Clients;

#if Matrix_Diagnostics
    using Matrix.Common.Diagnostics;
#endif

namespace Matrix.Framework.SuperPool.Call
{
    /// <summary>
    /// Stores information on synchronous (or asynchronous but waiting for a result) super pool calls.
    /// </summary>
    public class SyncCallInfo : IDisposable
    {
        #region Common

        public DateTime CreationTime { get; protected set; }
        public long CallId { get; protected set; }

        #endregion

        public object Response { get; set; }
        public SuperPoolCall RequestCall { get; set; }
        public ManualResetEvent Event { get; set; }
        public Exception Exception { get; protected set; }

        #region Async Result Waiting Call

        public AsyncCallResultDelegate AsyncResultDelegate { get; set; }
        public object AsyncResultState { get; set; }
        /// <summary>
        /// Used when a call was made to any implementor, and results are collection in 
        /// async fashion, with this max. timeout allowed for a result.
        /// </summary>
        public TimeSpan? AsyncResultTimeout { get; set; }

        #endregion

        /// <summary>
        /// A multi response call is waiting for multiple results to come in.
        /// </summary>
        public bool IsMultiResponse
        {
            get
            {
                return (AsyncResultDelegate != null && AsyncResultTimeout.HasValue);
            }
        }

        public bool IsMultiResponseComplete
        {
            get
            {
                return (AsyncResultDelegate != null && AsyncResultTimeout.HasValue
                        && (DateTime.Now - CreationTime) > AsyncResultTimeout.Value);
            }
        }

        /// <summary>
        /// Constructor.
        /// </summary>
        public SyncCallInfo(long callId)
        {
            this.CallId = callId;
            CreationTime = DateTime.Now;
        }

        public void AcceptResponse(SuperPoolClient client, object result, Exception exception)
        {
            Response = result;

            if (AsyncResultDelegate != null)
            {
                try
                {
                    AsyncResultDelegate.Invoke(client, new AsyncResultParams() { Result = result, State = AsyncResultState, Exception = exception });
                }
                catch (Exception ex)
                {
#if Matrix_Diagnostics
                    SystemMonitor.OperationError(string.Format("AcceptReposnse invoke of client [{0}] has caused an exception", client.Name), ex);
#endif
                }
            }
            else
            {// Assign the parameter only in sync calls, since async already consumed it trough async delegate.
                Exception = exception;
            }

            ManualResetEvent eventInstance = Event;
            if (eventInstance != null)
            {
                eventInstance.Set();
            }
        }

        #region IDisposable Members

        public void Dispose()
        {
            Response = null;
            
            ManualResetEvent eventInstance = Event;
            if (eventInstance != null)
            {// Release the waiting thread.
                eventInstance.Set();
            }
        }

        #endregion
    }
}
